package mrusanov.view

import java.awt.{ Point, Graphics2D, Graphics }
import sun.net.www.content.text.plain
import mrusanov.battle.PlayerState
import mrusanov.sounds.SpriteSoundConfiguration

class PlayerSprite(val playerState: PlayerState, info: PlayerSpriteInfo, host: Boolean, soundConfiguration: SpriteSoundConfiguration,
	effectInfo: Option[GraphicEffectInfoConfig] = None, frameTime: Int = 50) {
	private val sprites: Map[PlayerViewState, Sprite] = loadSpritesForViewState

	private var currentEffect: Option[GraphicEffect] = None
	private var _state: PlayerViewState = Stand

	var coordinates = new Point()

	var soundsEnabled = true

	private var attackResult: Option[Boolean] = None

	def x = coordinates.x
	def y = coordinates.y

	def loadSpritesForViewState: Map[PlayerViewState, Sprite] = {
		info.images.map(kv => (kv._1, Sprite(kv._2, host)))
	}

	def state = _state
	def state_=(state: PlayerViewState, successful: Option[Boolean] = None) {
		require((state == Defence || state == AttackDown || state == AttackUp) ^ successful.isEmpty,
			"Successful is " + successful.isDefined + " with state " + state.name)

		if (_state == Defence && state != Death && attackResult.get) {
			if (soundsEnabled) {
				soundConfiguration.playHitSound()
			}
		}

		_state = state
		attackResult = successful
		if (state != NotRender) {
			currentSprite.reset()
		}

		if (state == AttackDown || state == AttackUp) {
			require(successful.isDefined, "Successful option is not defined")
			if (soundsEnabled) {
				soundConfiguration.playAttackSoundIfNeeded(attackResult.get, 0)
			}

			val up = state == AttackUp
			currentEffect = effectInfo.map(ef => GraphicEffect(ef.name, success = successful.get, up = up))
			currentEffect.foreach(_.initEffect(coordinates, enemyPosition(up)))
		}

		if (state == Death) {
			if (soundsEnabled) {
				soundConfiguration.playDeathSound()
			}
		}
	}

	private def enemyPosition(enemyIsUp: Boolean) = enemyIsUp match {
		case true => new Point(x, y - 72)
		case false => new Point(x, y + 72)
	}

	def index = currentSprite.index

	private def currentSprite = sprites(_state)

	def update(time: Int) {
		if (state == NotRender) {
			return
		}

		val changed = currentSprite.update(time)
		if (changed && state.isAttack) {
			assert(attackResult.isDefined, "Attack result is not defined!")
			if (soundsEnabled) {
				soundConfiguration.playAttackSoundIfNeeded(attackResult.get, index)
			}
		}

		if (currentEffect.isDefined) {
			if (currentSprite.index >= effectInfo.get.startingIndex) {
				currentEffect.get.update(time)
			}
		}

		if (isCurrentSpriteOver) {
			state = if (state == Death) NotRender
			else Stand
			currentEffect = None
		}
	}

	private def isCurrentSpriteOver = currentSprite.isOver && currentEffect.forall(_.over)

	def render(g: Graphics2D) {
		if (state == NotRender) {
			return
		}

		currentSprite.x = x
		currentSprite.y = y
		currentSprite.render(g)

		currentEffect.foreach(_.render(g))
	}
}
